#pragma once
#ifndef __FIXEDDEQUE_H_INCLUDED__
#define __FIXEDDEQUE_H_INCLUDED__

#include "glf/fstl/fixed_base.h"

namespace glf {

template<typename T, size_t N>
struct fixed_deque {
	typedef T					value_type;
	typedef T*					pointer;
	typedef const pointer		const_pointer;
	typedef T&					reference;
	typedef const T&			const_reference;
	typedef size_t				size_type;
	typedef ptrdiff_t			difference_type;
	
	typedef fixed_deque<T, N>	this_type;

	fixed_deque() :
		mSize(0),
		mHead(0) {
	}
	explicit fixed_deque(size_t n) :
		mSize(0),
		mHead(0) {
		construct_n(n, T()); 
	}
	fixed_deque(size_t n, const_reference elem) :
		mSize(0),
		mHead(0) {
		construct_n(n, elem);
	}	
	~fixed_deque() {
		resize(0);
	}
	void resize(size_type n) {
		resize(n, T());
	}
	void resize(size_type n, T elem) {
		if(n < size()) {
			//destruct_n(size(), size()-n);
		} else if(n < N) {
			//construct_n(size(), n - size(), elem);
		} else {
			//do nothing ??
		}
	}

	void push_front(const_reference elem) {
		construct_n(1, elem);
	}
	void push_back(const_reference elem) {
		construct_n(1, elem);
		
	}
	void pop_back() {
		
	}
	void pop_front() {
		
	}
	reference back() {
		GLF_ASSERT(mSize > 0);
		return at(mSize-1);
	}
	const_reference back() const {
		GLF_ASSERT(mSize > 0);
		return 0;
	}
	reference front() {
		GLF_ASSERT(mSize > 0);
		return at(0);
	}
	const_reference front() const {
		GLF_ASSERT(mSize > 0);
		return at(0);
	}

	size_t size() const {
		return mSize;
	}
	size_t max_size() const {
		return N;
	}
	bool empty() const {
		return mSize == 0;
	}
	reference operator[](size_type n) {
		return at(n);
	}
	const_reference operator[](size_type n) const {
		return at(n);
	}
private:
	fixed_deque(const this_type& right);
	reference operator=(const this_type& right);
	void swap(this_type&);

	size_t idx(size_t idx) const {
		size_t nidx = mHead + idx;
		
		if(nidx >= N) {
			nidx -= N;
		}
		
		return nidx;
	}

	reference at(size_t idx) {
		return *(reinterpret_cast<T*>(mBuffer) + idx);
	}

	const_reference at(size_t idx) const {
		return *(reinterpret_cast<T*>(mBuffer) + idx);
	}

	void* ptr(size_t idx) {
		return reinterpret_cast<T*>(mBuffer) + idx;
	}

	void construct_n(size_t n, const_reference val) {
		size_t startIdx = size();
		for(size_t i = 0; i < n; ++i) {
			new (ptr(startIdx+i)) T(val);
		}
		mSize += n;
	}
	
	void destruct_n(size_t startIdx, size_t num) {
		for(size_t i = 0; i < num; ++i) {
			at(startIdx-1-i).~T();
		}
		mSize -= num;
	}

	pointer fill_n(pointer p, size_type s, const_reference v) {
		return 0;
	}

	//void insert_n(const_iterator _Where, size_type n, const_reference v) {
	//}

	size_t mSize;
	size_t mHead;
	
	char mBuffer[sizeof(T) * N];
};

}

#endif